#include "dma.h"

void i86_dma_set_address(uint8_t channel,uint16_t physicalAddress)
{
	if(channel > 8)
		return;

	uint16_t port;

	switch (channel)
	{
	case 0:
		port = DMA0_CHAN0_ADDR_REG;break;
	case 1:
		port = DMA0_CHAN1_ADDR_REG;break;
	case 2:
		port = DMA0_CHAN2_ADDR_REG;break;
	case 3:
		port = DMA0_CHAN3_ADDR_REG;break;
	case 4:
		port = DMA1_CHAN4_ADDR_REG;break;
	case 5:
		port = DMA1_CHAN5_ADDR_REG;break;
	case 6:
		port = DMA1_CHAN6_ADDR_REG;break;
	case 7:
		port = DMA1_CHAN7_ADDR_REG;break;
	}

	outportb(port,physicalAddress & 0x00ff);
	outportb(port,(physicalAddress & 0xff00) >> 8);
}

void i86_dma_set_counter(uint8_t channel,uint16_t length)
{
	if(channel > 8)
		return;

	uint16_t port;

	switch (channel)
	{
	case 0:
		port = DMA0_CHAN0_COUNT_REG;break;
	case 1:
		port = DMA0_CHAN1_COUNT_REG;break;
	case 2:
		port = DMA0_CHAN2_COUNT_REG;break;
	case 3:
		port = DMA0_CHAN3_COUNT_REG;break;
	case 4:
		port = DMA1_CHAN4_COUNT_REG;break;
	case 5:
		port = DMA1_CHAN5_COUNT_REG;break;
	case 6:
		port = DMA1_CHAN6_COUNT_REG;break;
	case 7:
		port = DMA1_CHAN7_COUNT_REG;break;
	}

	outportb(port,length & 0x00ff);
	outportb(port,(length & 0xff00) >> 8);
}

void i86_dma_mask_channel(uint8_t channel)
{
	if(channel >= 4)
		outportb(DMA1_MASK_REG,(channel - 4) & 4);
	else
		outportb(DMA0_MASK_REG,channel & 4);
}

void i86_dma_unmask_channel(uint8_t channel)
{
	if(channel >= 4)
		outportb(DMA1_MASK_REG,(channel - 4));
	else
		outportb(DMA0_MASK_REG,channel);
}

void i86_dma_unmask_all()
{
	outportb(DMA1_UNMASK_ALL_REG,0xff);
}

void i86_dma_set_mode(uint8_t channel,uint8_t cmd)
{
	i86_dma_mask_channel(channel);
	outportb((channel >= 4 ? DMA1_MODE_REG : DMA0_MODE_REG),(channel >= 4 ? channel - 4 : channel) | cmd);
	i86_dma_unmask_all();
}

void i86_dma_set_read(uint8_t channel)
{
	i86_dma_set_mode(channel,DMA_MODE_TRANSFER_SINGLE | DMA_MODE_READ_TRANSFER);
}

void i86_dma_set_write(uint8_t channel)
{
	i86_dma_set_mode(channel,DMA_MODE_TRANSFER_SINGLE | DMA_MODE_WRITE_TRANSFER);
}

void i86_dma_clear_bytes_point(uint8_t dma)
{
	outportb(dma ? DMA1_CLEARBYTE_FLIPFLOP_REG : DMA0_CLEARBYTE_FLIPFLOP_REG,0xff);
}

void i86_dma_reset(uint8_t dma)
{
	outportb(dma ? 0x0d : 0xda,0xff);
}